home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1996 September
/
CHIP Eylül 1996.iso
/
utils
/
povray
/
povsrc.lzh
/
machine
/
unix
/
xwindows.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
18KB
|
621 lines
/****************************************************************************
* xwindows.c
*
* This module implements X-windows specific routines.
*
* from Persistence of Vision Raytracer
* Copyright 1993 Persistence of Vision Team
*---------------------------------------------------------------------------
* NOTICE: This source code file is provided so that users may experiment
* with enhancements to POV-Ray and to port the software to platforms other
* than those supported by the POV-Ray Team. There are strict rules under
* which you are permitted to use this file. The rules are in the file
* named POVLEGAL.DOC which should be distributed with this file. If
* POVLEGAL.DOC is not available or for more info please contact the POV-Ray
* Team Coordinator by leaving a message in CompuServe's Graphics Developer's
* Forum. The latest version of POV-Ray may be found there as well.
*
* This program is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
*
*****************************************************************************/
/*
* Here are some routines I wrote which implement +d option on unix computers
* running X-windows. For now, only black and white output is supported. If I
* get access to a computer with a color monitor, I'll probably add support
* for colors to my routines.
*
* In future I'll probably add some more dithering methods. I have tested these
* routines on SUN 3 and SUN 4. I'm using the tvtwm window manager.
*
* If you have some suggestions to my source code or if you change anything,
* please let me know. I can be reached at the following address: Marek
* Rzewuski, Avstikkeren 11, 1156 Oslo 11, Norway or marekr@ifi.uio.no on
* Internet.
*/
/*
* 91-07-29 Allan H. Wax (Wax.OSBU_South@Xerox.COM) Hacked this module so it
* can be used with either a colour or B&W screen. Made all variables local
* to this routine (no need for more globals if no one ever uses them). Fixed
* bug in refresh routine. Use dither from colorx.c. Use xpov.icon instead of
* theIcon.
*/
#include <stdio.h>
#include <X11/Xlib.h> /* some Xlib stuff */
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include "xpov.icn"
#include <math.h>
#include "frame.h"
#include "povproto.h"
#define BORDER_WIDTH 2
#define EV_MASK (ButtonPressMask | \
KeyPressMask | \
ExposureMask | \
StructureNotifyMask)
static Display *theDisplay;
static int theScreen;
static int theDepth;
static unsigned long theBlackPixel;
static unsigned long theWhitePixel;
static XEvent theEvent;
static Window theWindow, openWindow();
static GC theGC;
static unsigned char *bitmap; /* pointer to our picture bitmap */
static unsigned char *bitmapPos;/* position to the last drawn pixel in our
* bitmap */
static char *display_name = 0;
static int disp_wide, disp_high;
static XImage *xi;
static char *data;
static XGCValues gcvalues;
static long colorpixels[256];
static Bool iscolor;
static int screen_open = 0;
struct {
void (*Init) ();
void (*Close) ();
void (*Finished) ();
void (*Plot) ();
} display;
/* global POVRay variables */
extern FRAME Frame;
extern unsigned int Options;
extern char DisplayFormat;
extern int First_Line;
/*
* Sets up a connection to the X server and stores informations about the
* enviroment
*/
static initX()
{
theDisplay = XOpenDisplay(NULL);
if (theDisplay == NULL) {
fprintf(stderr, "ERROR: Cannot establish a connection to the X server %s\n",
XDisplayName(NULL));
exit(1);
}
theScreen = DefaultScreen(theDisplay);
theDepth = DefaultDepth(theDisplay, theScreen);
theWhitePixel = WhitePixel(theDisplay, theScreen);
theBlackPixel = BlackPixel(theDisplay, theScreen);
}
/*
* This procedure will do the following things: 1) Set up attributes
* desired for the window 2) Set up an icon to our window. 3) Send
* hints to the window manager. 4) Open a window on the display 5) Tell
* the X to place the window on the screen 6) Flush out all the queued up X
* requests to the X server
*/
static Window openWindow(x, y, width, height, flag, theNewGC)
int x, y;
int width, height;
int flag;
GC *theNewGC;
{
XSetWindowAttributes theWindowAttributes;
XSizeHints theSizeHints;
unsigned long theWindowMask;
Window theNewWindow;
Pixmap theIconPixmap;
XWMHints theWMHints;
/*
* Set up some attributes for the window. Override_redirect tells the
* window manager to deal width the window or leave it alone
*/
theWindowAttributes.border_pixel = theBlackPixel;
theWindowAttributes.background_pixel = theWhitePixel;
theWindowAttributes.override_redirect = False;
theWindowMask = CWBackPixel | CWBorderPixel | CWOverrideRedirect;
/* Now, open out window */
theNewWindow = XCreateWindow(theDisplay,
RootWindow(theDisplay, theScreen),
x, y,
width, height,
BORDER_WIDTH,
theDepth,
InputOutput,
CopyFromParent,
theWindowMask,
&theWindowAttributes);
/* Create one iconbitmap */
theIconPixmap = XCreateBitmapFromData(theDisplay,
theNewWindow,
xpov_bits,
xpov_width,
xpov_height);
/*
* Now tell the window manager where on screen we should place our
* window.
*/
theWMHints.icon_pixmap = theIconPixmap;
theWMHints.initial_state = NormalState; /* we don't want an iconized
* window when it's created */
theWMHints.flags = IconPixmapHint | StateHint;
XSetWMHints(theDisplay, theNewWindow, &theWMHints);
theSizeHints.flags = PPosition | PSize;
theSizeHints.x = x;
theSizeHints.y = y;
theSizeHints.width = width;
theSizeHints.height = height;
/*
* theSizeHints.min_width = width; theSizeHints.min_height =
* height; theSizeHints.max_width = width; theSizeHints.max_height =
* height;
*/
XSetNormalHints(theDisplay, theNewWindow, &theSizeHints);
if (createGC(theNewWindow, theNewGC) == 0) {
XDestroyWindow(theDisplay, theNewWindow);
return ((Window) 0);
}
/* make a name for our window */
XStoreName(theDisplay, theNewWindow, "POVRay \0");
/*
* Now, could we please see the window on the screen? Until now, we have
* dealed with a window which has been created but noe appeared on the
* screen. Maping the window places it visibly on the screen
*/
XMapWindow(theDisplay, theNewWindow);
XFlush(theDisplay);
return (theNewWindow);
}
static refreshWindow(theExposedWindow)
Window theExposedWindow;
{
int i = 0, x = 0, y = First_Line;
register unsigned char *dummy = bitmap;
while (dummy != bitmapPos) {
/* draw until most current pixel is drawn */
if (*dummy)
XDrawPoint(theDisplay, theWindow, theGC, x, y);
if (x == Frame.Screen_Width) {
x = 0;
y++;
}
else {
dummy++;
x++;
i++;
}
}
XFlush(theDisplay);
}
/* Creates a new graphics context */
static int createGC(theNewWindow, theNewGC)
Window theNewWindow;
GC *theNewGC;
{
XGCValues theGCValues;
*theNewGC = XCreateGC(theDisplay,
theNewWindow,
(unsigned long) 0,
&theGCValues);
if (*theNewGC == 0) {
return (0); /* error */
}
else { /* set foreground and background defaults for
* the new GC */
XSetForeground(theDisplay,
*theNewGC,
theBlackPixel);
XSetBackground(theDisplay,
*theNewGC,
theWhitePixel);
return (1); /* OK */
}
}
static initEvents(theWindow)
Window theWindow;
{
XSelectInput(theDisplay,
theWindow,
EV_MASK);
}
void BWFinished()
{
}
void BWInit()
{
int i;
/*
* set some room for a bitmap for our picture. I've got to "remember" the
* whole picture bacuse of resizing of the window, overlapping etc. Then
* I've got to refresh the picture. This should be easy to convert to an
* "color version" in future
*/
bitmap = (unsigned char *) malloc(sizeof(unsigned char) *
(Frame.Screen_Width * Frame.Screen_Height));
bitmapPos = bitmap;
if (bitmap == NULL)
printf("ERROR: Can not allocate the buffer..\n");
for (i = 0; i < (Frame.Screen_Width * Frame.Screen_Height); i++) {
*bitmapPos++ = 0;
}
bitmapPos = bitmap;
initX();
theWindow = openWindow(0, 0, Frame.Screen_Width, Frame.Screen_Height, 0, &theGC);
initEvents(theWindow);
XFlush(theDisplay);
XNextEvent(theDisplay, &theEvent);
XFlush(theDisplay);
} /* end of display initilazation */
void BWClose()
{
sleep(10); /* an simple delay. 10 seconds. */
XDestroyWindow(theDisplay, theWindow);
XFlush(theDisplay);
XCloseDisplay(theDisplay);
free(bitmap);
}
void BWPlot(x, y, Red, Green, Blue)
int x, y;
unsigned char Red, Green, Blue;
{
unsigned char color;
long thePixel;
/* lets find if there are some events waiting for us */
while (XPending(theDisplay) > 0) { /* now deal with the events.. */
XNextEvent(theDisplay, &theEvent);
switch (theEvent.type) {
case Expose:
/* printf("Window is exposed.\n"); */
refreshWindow(theEvent.xany.window);
break;
case MapNotify:
/* printf("The window is mapped.\n"); */
refreshWindow(theEvent.xany.window);
break;
case ButtonPress:
/* printf("A mouse button was pressed.\n"); */
break;
case ConfigureNotify:
/* printf("The window configuration has been changed\n"); */
refreshWindow(theEvent.xany.window);
break;
}
}
if (dither(x, y, Red, Green, Blue)) {
thePixel = BlackPixel(theDisplay, theScreen);
XDrawPoint(theDisplay, theWindow, theGC, x, y);
XFlush(theDisplay);
}
else {
thePixel = WhitePixel(theDisplay, theScreen);
}
*bitmapPos++ = thePixel;
}
/* so we can get at the dimensions */
extern FRAME Frame;
/* x11 stuff */
static Bool evtPred(d, e, a)
Display *d;
XEvent *e;
char *a;
{
return (True);
}
static void BuildColormap()
{
XColor tmp;
register unsigned short r, g, b, i;
Colormap cmap;
/*
* build a colormap that will contain 216, or 6^3 colors. We won't do
* anything clever like adding extra grays in the leftover space.
* Remember, this was written in a few hours.
*/
cmap = DefaultColormap(theDisplay, theScreen);
i = 0;
for (r = 0; r < 6; r++) {
for (g = 0; g < 6; g++) {
for (b = 0; b < 6; b++, i++) {
tmp.red = (r * 36) << 8;
tmp.green = (g * 36) << 8;
tmp.blue = (b * 36) << 8;
tmp.flags = DoRed | DoGreen | DoBlue;
if (!XAllocColor(theDisplay, cmap, &tmp))
goto crap_out;
colorpixels[i] = tmp.pixel;
}
}
}
crap_out: /* couldn't get what we wanted. Boo-hoo. */
if (i != 216)
fprintf(stderr, "warning: could only get %d colors.\n", i);
}
void ColourFinished()
{
XEvent *report;
/* do nothing. I suppose we could wait... */
while (1) {
XNextEvent(theDisplay, &report);
XPutImage(theDisplay, theWindow, theGC, xi, 0, 0, 0, 0, Frame.Screen_Width,
Frame.Screen_Height);
}
}
void display_close()
{
if(screen_open)
(display.Close) ();
}
void display_plot(x, y, Red, Green, Blue)
int x, y;
unsigned char Red, Green, Blue;
{
(display.Plot) (x, y, Red, Green, Blue);
}
void display_finished()
{
if(screen_open)
(display.Finished) ();
}
void ColourInit()
{
Pixmap icon;
XSizeHints hints;
long size, i;
XSetWindowAttributes attrib;
if ((theDisplay = XOpenDisplay(display_name)) == NULL) {
fprintf(stderr, "Can't open X server %s.\n",
XDisplayName(display_name));
exit(1);
}
theScreen = DefaultScreen(theDisplay);
/* screen dimensions */
disp_wide = DisplayWidth(theDisplay, theScreen);
disp_high = DisplayHeight(theDisplay, theScreen);
theWindow = XCreateSimpleWindow(theDisplay, RootWindow(theDisplay, theScreen),
(disp_wide - Frame.Screen_Width) / 2,
(disp_high - Frame.Screen_Height) / 2,
Frame.Screen_Width,
Frame.Screen_Height, 2 /* border width */ ,
BlackPixel(theDisplay, theScreen), WhitePixel(theDisplay, theScreen));
/* create a graphics context for drawing */
gcvalues.function = GXcopy;
theGC = XCreateGC(theDisplay, theWindow, GCFunction, &gcvalues);
/* make a cute icon */
icon = XCreateBitmapFromData(theDisplay, theWindow, xpov_bits, xpov_width,
xpov_height);
/* give a few clues about ourself */
hints.flags = PPosition | PSize | PMinSize;
hints.x = (disp_wide - Frame.Screen_Width) / 2;
hints.y = (disp_high - Frame.Screen_Height) / 2;
hints.width = Frame.Screen_Width;
hints.height = Frame.Screen_Height;
hints.min_width = 32;
hints.min_height = 32;
XSetStandardProperties(theDisplay, theWindow, "povray", "povray", icon, NULL, 0,
&hints);
/* only want to know about expose events */
XSelectInput(theDisplay, theWindow, ExposureMask);
XMapWindow(theDisplay, theWindow);
BuildColormap();
size = Frame.Screen_Width * Frame.Screen_Height;
data = (char *) XtMalloc(size);
for (i = 0; i < size; i++)
data[i] = 0;
xi = XCreateImage(theDisplay, DefaultVisual(theDisplay, theScreen), 8, ZPixmap, 0, data,
Frame.Screen_Width, Frame.Screen_Height, 8, Frame.Screen_Width);
};
void ColourClose()
{
sleep(10);
XDestroyImage(xi);
XtFree(data);
XDestroyWindow(theDisplay, theWindow);
XCloseDisplay(theDisplay);
}
/* static */ int dither(x, y, Red, Green, Blue)
register unsigned int x, y;
unsigned char Red, Green, Blue;
{
/*
* Perform ordered dithering for halftone screen. For details, see
* Graphics Gems, Ed. Andrew Glassner, p. 176-178 Floyd-Steinberg dither
* would look better, but we would need more saved state, making the
* coding a lot uglier. Since this is just a display hack and not an
* image processing package, I don't bother.
*/
static unsigned int dm[] = {
0, 192, 48, 240, 12, 204, 60, 252,
128, 64, 176, 112, 140, 76, 188, 124,
32, 224, 16, 208, 44, 236, 28, 220,
160, 96, 144, 80, 172, 108, 156, 92,
8, 200, 56, 248, 4, 196, 52, 244,
136, 72, 184, 120, 132, 68, 180, 116,
40, 232, 24, 216, 36, 228, 20, 212,
168, 104, 152, 88, 164, 100, 148, 84
};
register unsigned long luminence =
(307 * Red + 599 * Green + 118 * Blue) / 1024;
return (luminence < dm[(x & 7) + ((y & 7) << 3)]);
}
void ColourPlot(x, y, Red, Green, Blue)
int x, y;
unsigned char Red, Green, Blue;
{
long thePixel;
int r, g, b;
XEvent report;
int luminence;
/* scale rgb to be in our 216 color space */
r = (Red * 216) / (256 * 36);
g = (Green * 216) / (256 * 36);
b = (Blue * 216) / (256 * 36);
/* find the pixel we got */
thePixel = colorpixels[(r * 36) + (g * 6) + b];
XPutPixel(xi, x, y, thePixel);
/* on each pixel, copy a scanline. Inefficient, but so what? See above. */
XPutImage(theDisplay, theWindow, theGC, xi, 0, y, 0, y, Frame.Screen_Width, 1);
/* poll for exposure events */
if (XCheckIfEvent(theDisplay, &report, evtPred, "blah")) {
XPutImage(theDisplay, theWindow, theGC, xi, 0, 0, 0, 0, Frame.Screen_Width, y + 1);
}
}
void unix_init_POVRAY PARAMS((void))
{
}
int matherr(x)
struct exception *x;
{
switch (x->type) {
case DOMAIN:
case OVERFLOW:
x->retval = 1.0e17;
break;
case SING:
case UNDERFLOW:
x->retval = 0.0;
break;
default:
break;
}
return (1);
}
extern void BWInit(), BWClose(), BWFinished(), BWPlot();
void display_init()
{
Pixmap icon;
XSizeHints hints;
long size, i;
XSetWindowAttributes attrib;
if ((theDisplay = XOpenDisplay(display_name)) == NULL) {
fprintf(stderr, "Can't open X server %s.\n",
XDisplayName(display_name));
exit(1);
}
screen_open = 1;
theScreen = DefaultScreen(theDisplay);
iscolor = (XDisplayCells(theDisplay, theScreen) > 2);
if (iscolor) {
display.Init = ColourInit;
display.Close = ColourClose;
display.Finished = ColourFinished;
display.Plot = ColourPlot;
}
else {
display.Init = BWInit;
display.Close = BWClose;
display.Finished = BWFinished;
display.Plot = BWPlot;
}
XCloseDisplay(theDisplay);
(display.Init) ();
}